package com.shen.cas;


import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * ABA问题的解决
 */
public class Demo03 {

    public static void main(String[] args) {
        /**
         * public AtomicStampedReference(V initialRef[初始值], int initialStamp[初始版本号])
         */
        AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<Integer>(1,1);

        /**
         * A线程
         */
        new Thread(()->{
            int stamp = atomicStampedReference.getStamp();//获得版本号
            System.out.println("a1====>"+stamp);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            /**
             * public boolean compareAndSet(V   expectedReference, 期望值
             *                                  V   newReference,  新的值
             *                                  int expectedStamp, 期望的版本号
             *                                  int newStamp)   新的版本号
             */
            System.out.println(atomicStampedReference.compareAndSet(1, 2,
                    atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
            System.out.println("a2====>"+atomicStampedReference.getStamp());

            System.out.println(atomicStampedReference.compareAndSet(2, 1,
                    atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
            System.out.println("a3====>"+atomicStampedReference.getStamp());

        },"A").start();

        /**
         * B线程
         */
        new Thread(()->{
            int stamp = atomicStampedReference.getStamp();//获得版本号
            System.out.println("b1====>"+stamp);


            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(atomicStampedReference.compareAndSet(1, 3,
                    atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
            System.out.println("b2====>"+atomicStampedReference.getStamp());


        },"B").start();


        /**
         * a1====>1
         * b1====>1
         * false
         * a2====>1
         * false
         * a3====>1
         * false
         * b2====>1
         *
         *      这里有一个坑
         *
         *   public boolean compareAndSet(V   expectedReference,
         *                                  V   newReference,
         *                                  int expectedStamp,
         *                                  int newStamp) {
         *         Pair<V> current = pair;
         *         return
         *             expectedReference == current.reference &&
         *             expectedStamp == current.stamp &&
         *             ((newReference == current.reference &&
         *               newStamp == current.stamp) ||
         *              casPair(current, Pair.of(newReference, newStamp)));
         *     }
         *
         * 这里使用的时compareAndSet使用的是==比较的，==比较的不仅是对象还有值
         *
         * 另外Integer在-128到127之间是有缓存的[IntegerCache]会复用这个缓存中对象，但当超过这个区间的值都会在堆上产生新的值
         *
         * 所以我们给的2020是一个超过-128到127之间的值，所以A线程和B线程操作的不是同一个对象，这就是上面未能修改成功的原因
         *
         * 另外所有相同类型的包装类之间值的比较最好使用equals方法比较
         *
         *
         */
    }
}
